package com.apex.oauth.security.configuration;

import com.apex.oauth.security.cas.component.CustomUserDetailsService;
import com.apex.oauth.security.cas.filter.HttpParamsFilter;
import com.apex.oauth.security.component.MyUrlAuthenticationSuccessHandler;
import com.apex.oauth.security.ice.component.CustomUserAuthenticationManager;
import com.apex.oauth.security.ice.component.MyAuthenticationSuccessHandler;
import com.apex.oauth.security.ice.component.MySimpleUrlAuthenticationFailureHandler;
import com.apex.oauth.security.ice.filter.UserLoginFilter;
import com.apex.oauth.security.service.impl.UserInformationServiceImpl;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.util.StringUtils;

/**
 * Create by IntelliJ IDEA
 * 用户：王建
 * 日期：2018-4-2
 */
@Configuration
@EnableWebSecurity
//开启Security注解支持
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

    /**
     * 身份认证类型
     * none:未启用身份认证
     * cas :使用cas
     * ice :使用ice
     */
    @Value("${sso.type:none}")
    private String ssoType;

    @Value("${sso.cas.server.host:http://localhost}")
    private String casServerHost;

    @Value("${sso.cas.server.login:/login}")
    private String casServerLogin;

    @Value("${sso.cas.server.logout:/logout}")
    private String casServerLogout;

    @Value("${sso.cas.service.host:http://localhost}")
    private String casClientHost;

    @Value("${sso.cas.service.login:/login}")
    private String casClientLogin;

    @Value("${sso.cas.service.logout:/logout}")
    private String casClientLogout;


    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    /**
     * 设置用户密码的加密方式为MD5加密
     *
     * @return
     */
    @Bean
    public Md5PasswordEncoder passwordEncoder() {
        return new Md5PasswordEncoder();
    }

    @Bean
    public UserInformationServiceImpl getUserService() {
        return new UserInformationServiceImpl();
    }

    /**
     * 认证方式
     *
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        if (StringUtils.isEmpty(ssoType) || "none".equals(ssoType)) {//未启用身份认证
            auth.userDetailsService(getUserService()).passwordEncoder(passwordEncoder());
        } else if ("cas".equals(ssoType)) {//使用cas
            super.configure(auth);
           /* auth.authenticationProvider(casAuthenticationProvider());*/
        } else if ("ice".equals(ssoType)) {//使用ice
            auth.authenticationProvider(customUserAuthenticationManager());
            /**设置不清除登录密码，此操作只限于开启金智ldap认证**/
            auth.eraseCredentials(false);
        }
    }

    /**
     * 设置认证拦截，指定登录页面
     *
     * @param http
     * @throws Exception
     */
    public void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().sameOrigin().httpStrictTransportSecurity().disable();
        //允许所有用户访问"/"和"/home",/static下面的默认不需要登录验证
        if (!StringUtils.isEmpty(ssoType) && "cas".equals(ssoType)) {
            http.authorizeRequests()//配置安全策略
                    .antMatchers("/s/**", "/rest/**").permitAll()//定义/请求不需要验证
                    .anyRequest().authenticated()//其余的所有请求都需要验证
                    .and()
                    .logout()
                    .permitAll()//定义logout不需要验证
                    .and()
                    .formLogin();//使用form表单登录
            /*http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
                    .and()
                    .addFilter(casAuthenticationFilter())
                    .addFilterBefore(casLogoutFilter(), LogoutFilter.class)
                    .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);*/
        } else if (!StringUtils.isEmpty(ssoType) && "ice".equals(ssoType)) {
            http.authorizeRequests()
                    .antMatchers("/s/**", "/rest/**").permitAll()
                    //其他地址的访问均需验证权限
                    .anyRequest().authenticated()
                    .and().addFilterBefore(userLoginFilter(), UsernamePasswordAuthenticationFilter.class)
                    .formLogin()
                    //指定登录页是"/login"
                    .loginPage("/login")
                    .failureUrl("/login?error=true")
                    .defaultSuccessUrl("/index")//登录成功后默认跳转到"/index"
                    .permitAll()
                    .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/login").
                    invalidateHttpSession(true).
                    permitAll();//退出登录后的默认url是"/login";
        } else {
            http.authorizeRequests()
                    .antMatchers("/s/**", "/rest/**").permitAll()
                    //其他地址的访问均需验证权限
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    //指定登录页是"/login"
                    .loginPage("/login")
                    .failureUrl("/login?error=true")
                    .defaultSuccessUrl("/index")//登录成功后默认跳转到"/index"
                    .permitAll()
                    .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/login").invalidateHttpSession(true)//退出登录后的默认url是"/login"
                    .permitAll();
        }
        //设置rest api不启用csrf拦截
        http.csrf().ignoringAntMatchers("/rest/**", "/s/**");
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置不拦截规则
        web.ignoring().antMatchers("/static/**");
    }

    /***********************cas相关配置***********************************/
    /**
     * 指定service相关信息
     */
   /* @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService(casClientHost + casClientLogin);
        serviceProperties.setAuthenticateAllArtifacts(true);
        return serviceProperties;
    }*/

    /**
     * 认证的入口
     */
    /*@Bean
    public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
        CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
        casAuthenticationEntryPoint.setLoginUrl(casServerLogin);
        casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
        return casAuthenticationEntryPoint;
    }*/

    /**
     * CAS认证过滤器
     */
    /*@Bean
    public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());
        casAuthenticationFilter.setFilterProcessesUrl(casClientLogin);
        casAuthenticationFilter.setContinueChainBeforeSuccessfulAuthentication(false);
        casAuthenticationFilter.setAuthenticationSuccessHandler(new MyUrlAuthenticationSuccessHandler("/"));
        return casAuthenticationFilter;
    }*/

    /**
     * cas 认证 Provider
     */
    /*@Bean
    public CasAuthenticationProvider casAuthenticationProvider() {
        CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
        //casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
        casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型，实现的接口不一样，都可以的。
        casAuthenticationProvider.setServiceProperties(serviceProperties());
        casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");
        return casAuthenticationProvider;
    }*/

   /* @Bean
    public UserDetailsService customUserDetailsService() {
        return new CustomUserDetailsService();
    }*/

    /**
     * 用户自定义的AuthenticationUserDetailsService
     */
   /* @Bean
    public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){
        return new CustomUserDetailsService();
    }*/
   /* @Bean
    public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
        return new Cas20ServiceTicketValidator(casServerHost);
    }*/

    /**
     * 单点登出过滤器
     */
    /*@Bean
    public SingleSignOutFilter singleSignOutFilter() {
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
        if ("cas".equals(ssoType)) {
            singleSignOutFilter.setCasServerUrlPrefix(casServerHost);
            singleSignOutFilter.setIgnoreInitConfiguration(true);
        }
        return singleSignOutFilter;
    }*/

    /**
     * 执行认证前，url地址及参数保存
     *
     * @return
     */
    @Bean
    public HttpParamsFilter getHttpParamsFilter() {
        return new HttpParamsFilter();
    }

   /* @Bean
    public FilterRegistrationBean httpParamsFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(getHttpParamsFilter());
        filterRegistrationBean.setOrder(-999);
        filterRegistrationBean.addUrlPatterns("/uc/*");
        return filterRegistrationBean;
    }*/

    /**
     * 请求单点退出过滤器
     */
   /* @Bean
    public LogoutFilter casLogoutFilter() {
        LogoutFilter logoutFilter = new LogoutFilter(casServerLogout, new SecurityContextLogoutHandler());
        logoutFilter.setFilterProcessesUrl(casClientLogout);
        return logoutFilter;
    }*/

    /***********************cas相关配置结束************************/
    /*#######################金智ice认证配置开始##########################*/
    @Bean
    public CustomUserAuthenticationManager customUserAuthenticationManager() {
        return new CustomUserAuthenticationManager();
    }

    @Bean
    public MySimpleUrlAuthenticationFailureHandler getMySimpleUrlAuthenticationFailureHandler() {
        return new MySimpleUrlAuthenticationFailureHandler("/login?error=true");
    }

    @Bean
    public MyAuthenticationSuccessHandler getMyAuthenticationSuccessHandler() {
        MyAuthenticationSuccessHandler myAuthenticationSuccessHandler = new MyAuthenticationSuccessHandler();
        return myAuthenticationSuccessHandler;
    }

    @Bean
    public UserLoginFilter userLoginFilter() throws Exception {
        UserLoginFilter filer = new UserLoginFilter();
        filer.setAuthenticationManager(authenticationManager());
        filer.setAuthenticationFailureHandler(getMySimpleUrlAuthenticationFailureHandler());
        filer.setAuthenticationSuccessHandler(getMyAuthenticationSuccessHandler());
        return filer;
    }
    /*#######################金智ice认证配置结束##########################*/
}
